#include <linux/module.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/msi.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/version.h>
#include "drv_pt100.h"

#define PT_CMD_CODE_MASK        0x0000FFFF      /* PT 指令码 掩码 */
#define PT_CMD_CODE_SHIFT       0               /* PT 指令码 偏移 */

#define PT_RANGE_MASK           0x03            /* PT 量程掩码 */
#define PT_RANGE_10V_LSB        305             /* 305uV */
#define PT_RANGE_2V5_LSB        76              /* 76uV */
#define PT_RANGE_5V_LSB         152             /* 152uV */
#define PT_DEF_RANGE            PT_RANGE_10V    /* PT 默认量程, 0: ±10V, 1: ±2.5V, 2: ±5V, 3: ±10V */

#define PT_MODE_MASK            0x00380000      /* PT 模式掩码 */
#define PT_OSR_MASK             0x00070000      /* PT 过采样掩码 */
#define PT_SAMPLE_MASK          0x0000FFFF      /* PT 采样间隔掩码 */
#define PT_MODE_SHIFT           19              /* PT 模式偏移 */
#define PT_OSR_SHIFT            16              /* PT 过采样偏移 */
#define PT_SAMPLE_SHIFT         0               /* PT 采样间隔偏移 */
#define PT_US_TO_HZ             1000000         /* PT us 转换到 Hz */
#define PT_DEF_MODE             PT_MOD_SMP      /* PT 默认模式 */
#define PT_DEF_OSR              0               /* PT 默认过采样, 0, 2, 4, 8, 16, 32, 64, 128 */
#define PT_DEF_SAMPLE           100000          /* PT 默认采样率, 1~100000Hz */

#define PT_MSI_MASK             0x01            /* PT MSI 掩码 */
#define PT_DMA_MSI_MASK         0x02            /* PT DMA MSI 掩码 */
#define PT_DMA_MSI_VEC          0               /* PT DMA MSI 中断向量 */
#define PT_TIM_MSI_VEC          18              /* PT TIM MSI 中断向量 */

#define PT_ID_MASK              0xFF000000      /* PT 通道掩码 */
#define PT_DATA_MASK            0x00FFFFFF      /* PT 数据掩码 */
#define PT_DATA_SIGN_MASK       0x0080000       /* PT 数据符号位掩码 */
#define PT_ID_SHIFT             24              /* PT 通道偏移 */
#define PT_DATA_SHIFT           0               /* PT 数据偏移 */

#define PT_DEF_DMA_SIZE         (64 * 1024)     /* PT DMA 大小 128KByte */

#define PT_SAMP_TIM_MASK        0xFFFF0000      /* PT 抽样定时间隔时间掩码 */
#define PT_SLID_WIN_MASK        0x0000FFFF      /* PT 滑动平均窗口掩码 */
#define PT_SAMP_TIM_SHIFT       16              /* PT 抽样定时间隔时间偏移 */
#define PT_SLID_WIN_SHIFT       0               /* PT 滑动平均窗口偏移 */
#define PT_DEF_SAMP_TIM         65535           /* PT 默认抽样定时间隔, 0~65535us */
#define PT_DEF_SLID_WIN         1               /* PT 默认滑动平均窗口, 1~32 个 */

/* PT 寄存器*/
enum pt_reg_t {
    PT_VERSION_OFFSET           = 0x04,         /* 版本 寄存器 */
    PT_CMD_OFFSET               = 0x08,         /* PT 指令寄存器偏移 */
    PT_CH_VAL_OFFSET            = 0x38,         /* PT 通道数据寄存器偏移*/
    PT_RANGE_OFFSET             = 0x44,         /* PT 范围寄存器偏移 */
    PT_MODE_OSR_SMP_OFFSET      = 0x48,         /* PT 模式、过采样和采样间隔寄存器偏移 */
    PT_MSI_MASK_OFFSET          = 0x60,         /* PT MSI 中断屏蔽寄存器偏移 */
    PT_DMA_LENGTH_OFFSET        = 0x68,         /* PT DMA 大小寄存器偏移 */
    PT_SAMP_SLID_WIN_OFFSET     = 0x80,         /* PT 抽样定时间隔时间、滑动平均窗口寄存器偏移 */
};

/* 文件操作函数声明 */
static int open_pt(struct inode *inode, struct file *filp);
static int release_pt(struct inode *inode, struct file *filp);
static ssize_t read_pt(struct file *filp, char __user *buf, 
                       size_t count, loff_t *ppos);
static long ioctl_pt(struct file *filp, unsigned int cmd, 
                     unsigned long arg);

/* 文件操作结构体 */
static const struct file_operations cdev_fops = {
    .owner = THIS_MODULE,
    .open = open_pt,
    .release = release_pt,
    .read = read_pt,
    .write = NULL,
    .unlocked_ioctl = ioctl_pt,
    .poll = NULL,
    .llseek = no_llseek,
};

/* 读取 PT 寄存器 */
static u32 read_pt_reg_le(struct pcie_dev_t *pcie_dev, u32 reg)
{
    u32 val = 0;
    unsigned long flags = 0;    /* 用于保存中断状态 */

    /* 获取自旋锁(保存中断状态) */
    spin_lock_irqsave(&pcie_dev->splock, flags);
    val = ioread32(pcie_dev->bar[0] + reg);
    /* 释放自旋锁(恢复中断状态) */
    spin_unlock_irqrestore(&pcie_dev->splock, flags);
    pr_debug("%s  reg=0x%08x, val=0x%08x", __func__, reg, val);

    return val;
}

/* 写入 PT 寄存器 */
static void write_pt_reg_le(struct pcie_dev_t *pcie_dev, u32 reg, u32 val)
{
    unsigned long flags = 0;    /* 用于保存中断状态 */

    /* 获取自旋锁(保存中断状态) */
    spin_lock_irqsave(&pcie_dev->splock, flags);
    iowrite32(val, pcie_dev->bar[0] + reg);
    /* 释放自旋锁(恢复中断状态) */
    spin_unlock_irqrestore(&pcie_dev->splock, flags);
    pr_debug("%s reg=0x%08x, val=0x%08x", __func__, reg, val);
}

/* 开始 PT 采集 */
static void start_pt_nolock(struct pt_ctrl_t *pctrl)
{
    pctrl->cmd = PT_CMD_START;
    pctrl->write_reg(pctrl->pcie_dev, PT_CMD_OFFSET, PT_CMD_START);
    dev_dbg(pctrl->dev, "Start PT success");
}

/* 停止 PT 采集 */
static void stop_pt_nolock(struct pt_ctrl_t *pctrl)
{
    pctrl->cmd = PT_CMD_STOP;
    pctrl->write_reg(pctrl->pcie_dev, PT_CMD_OFFSET, PT_CMD_STOP);
    dev_dbg(pctrl->dev, "Stop PT success");
}

/* 配置 PT 参数 */
static void config_pt_nolock(struct pt_ctrl_t *pctrl)
{
    pctrl->cmd = PT_CMD_CONFIG;
    pctrl->write_reg(pctrl->pcie_dev, PT_CMD_OFFSET, PT_CMD_CONFIG);
    dev_dbg(pctrl->dev, "Config PT success");
}

/* 配置 PT 模式 */
static int set_pt_mode(struct pt_ctrl_t *pctrl, u8 mode)
{
    u8 mode_code = mode;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    switch (mode) {
    case PT_MOD_SMP:
    case PT_MOD_SMP_TIM:
        break;
    case PT_MOD_RAW_DMA:
        break;
    case PT_MOD_RAW:
        break;
    default:
        mode_code = PT_DEF_MODE;
        dev_warn(pctrl->dev, "PT mode %d not support, use default %d", mode, mode_code);
        break;
    }
    pctrl->mode = mode_code;
    val = pctrl->read_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET);
    val &= (~PT_MODE_MASK);
    val |= (mode_code << PT_MODE_SHIFT);
    pctrl->write_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET, val);
    dev_dbg(pctrl->dev, "Set PT mode %d success", mode_code);
    /* 配置 PT 参数 */
    config_pt_nolock(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return 0;
}

/* 获取 PT 模式 */
static int get_pt_mode(struct pt_ctrl_t *pctrl)
{
    int ret = 0;
    u32 val = 0; 

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET);
    pctrl->chk_mode = ((val & PT_MODE_MASK) >> PT_MODE_SHIFT);
    if (pctrl->chk_mode != pctrl->mode) {
        dev_err(pctrl->dev, "Get PT mode %d, not the set %d", pctrl->chk_mode, pctrl->mode);
        ret = -EFAULT;
        goto unlock;
    } else {
        switch (pctrl->chk_mode) {
        case PT_MOD_SMP:
        case PT_MOD_SMP_TIM:
        case PT_MOD_RAW_DMA:
        case PT_MOD_RAW:
            dev_dbg(pctrl->dev, "Get PT mode %d, is the set %d", pctrl->chk_mode, pctrl->mode);
            break;
        default:
            dev_err(pctrl->dev, "Get PT mode %d not support", pctrl->chk_mode);
            ret = -EFAULT;
            goto unlock;
        }
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 配置 PT 过采样 */
static int set_pt_osr(struct pt_ctrl_t *pctrl, u8 osr)
{
    u8 osr_code = osr;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    switch (osr) {
    case PT_OSR_0:
    case PT_OSR_2:
    case PT_OSR_4:
    case PT_OSR_8:
    case PT_OSR_16:
    case PT_OSR_32:
    case PT_OSR_64:
    case PT_OSR_128:
        break;
    default:
        osr_code = PT_DEF_OSR;
        dev_warn(pctrl->dev, "PT OSR %d not support, use default %d", osr, osr_code);
        break;
    }
    pctrl->osr = osr_code;
    val = pctrl->read_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET);
    val &= (~PT_OSR_MASK);
    val |= ((osr_code << PT_OSR_SHIFT) & PT_OSR_MASK);
    pctrl->write_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET, val);
    dev_dbg(pctrl->dev, "Set PT OSR %d success", osr);
    /* 配置 PT 参数 */
    config_pt_nolock(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return 0;
}

/* 获取 PT 过采样 */
static int get_pt_osr(struct pt_ctrl_t *pctrl)
{
    int ret = 0;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET);
    pctrl->chk_osr = ((val & PT_OSR_MASK) >> PT_OSR_SHIFT);
    if (pctrl->chk_osr != pctrl->osr) {
        dev_err(pctrl->dev, "Get PT OSR %d, not the set %d", pctrl->chk_osr, pctrl->osr);
        ret = -EFAULT;
        goto unlock;
    } else {
        switch (pctrl->chk_osr) {
        case PT_OSR_0:
        case PT_OSR_2:
        case PT_OSR_4:
        case PT_OSR_8:
        case PT_OSR_16:
        case PT_OSR_32:
        case PT_OSR_64:
        case PT_OSR_128:
            dev_dbg(pctrl->dev, "Get PT OSR %d, is the set %d", pctrl->chk_osr, pctrl->osr);
            break;
        default:
            dev_err(pctrl->dev, "Get PT OSR %d not support", pctrl->chk_osr);
            ret = -EFAULT;
            goto unlock;
        }
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 配置 PT 采样率 */
static int set_pt_samp_rate(struct pt_ctrl_t *pctrl, u32 rate)
{
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    pctrl->samp_rate = rate;
    pctrl->interval = PT_US_TO_HZ / pctrl->samp_rate;       /* Hz to us*/
    val = pctrl->read_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET);
    val &= (~PT_SAMPLE_MASK);
    val |= ((pctrl->interval << PT_SAMPLE_SHIFT) & PT_SAMPLE_MASK);
    pctrl->write_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET, val);
    dev_dbg(pctrl->dev, "Set PT sample rate %dus %dHz success", pctrl->interval, pctrl->samp_rate);
    /* 配置 PT 参数 */
    config_pt_nolock(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return 0;
}

/* 获取 PT 采样率 */
static int get_pt_samp_rate(struct pt_ctrl_t *pctrl)
{
    int ret = 0;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_MODE_OSR_SMP_OFFSET);
    pctrl->chk_interval = ((val & PT_SAMPLE_MASK) >> PT_SAMPLE_SHIFT);
    pctrl->chk_samp_rate = PT_US_TO_HZ / pctrl->chk_interval;       /* us to Hz*/
    if (pctrl->chk_interval != pctrl->interval || 
        pctrl->chk_samp_rate != pctrl->samp_rate) {
        dev_err(pctrl->dev, "Get PT sample rate %dus %dHz, not the set %dus %dHz", 
                pctrl->chk_interval, pctrl->chk_samp_rate, pctrl->interval, pctrl->samp_rate);
        ret = -EFAULT;
        goto unlock;
    } else {
        dev_dbg(pctrl->dev, "Get PT sample rate %dus %dHz, is the set %dus %dHz", 
                pctrl->chk_interval, pctrl->chk_samp_rate, pctrl->interval, pctrl->samp_rate);
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 配置 PT 抽样定时间隔 */
static int set_pt_samp_tim(struct pt_ctrl_t *pctrl, u16 samp_tim)
{
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    pctrl->samp_tim = samp_tim;
    val = pctrl->read_reg(pctrl->pcie_dev, PT_SAMP_SLID_WIN_OFFSET);
    val &= (~PT_SAMP_TIM_MASK);
    val |= (samp_tim << PT_SAMP_TIM_SHIFT);
    pctrl->write_reg(pctrl->pcie_dev, PT_SAMP_SLID_WIN_OFFSET, val);
    dev_dbg(pctrl->dev, "Set PT sample time %dus success", samp_tim);
    /* 配置 PT 参数 */
    config_pt_nolock(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return 0;
}

/* 获取 PT 抽样定时间隔 */
static int get_pt_samp_tim(struct pt_ctrl_t *pctrl)
{
    int ret = 0;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_SAMP_SLID_WIN_OFFSET);
    pctrl->chk_samp_tim = ((val & PT_SAMP_TIM_MASK) >> PT_SAMP_TIM_SHIFT);
    if (pctrl->chk_samp_tim != pctrl->samp_tim) {
        dev_err(pctrl->dev, "Get PT sample time %d, not the set %d", 
                pctrl->chk_samp_tim, pctrl->samp_tim);
        ret = -EFAULT;
        goto unlock;
    } else {
        dev_dbg(pctrl->dev, "Get PT sample time %d, is the set %d", 
                pctrl->chk_samp_tim, pctrl->samp_tim);
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 配置 PT 滑动平均窗口 */
static int set_pt_slid_win(struct pt_ctrl_t *pctrl, u16 slid_win)
{
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    pctrl->slid_win = slid_win;
    val = pctrl->read_reg(pctrl->pcie_dev, PT_SAMP_SLID_WIN_OFFSET);
    val &= (~PT_SLID_WIN_MASK);
    val |= (slid_win << PT_SLID_WIN_SHIFT);
    pctrl->write_reg(pctrl->pcie_dev, PT_SAMP_SLID_WIN_OFFSET, val);
    dev_dbg(pctrl->dev, "Set PT slide window %d success", slid_win);
    /* 配置 PT 参数 */
    config_pt_nolock(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return 0;
}

/* 获取 PT 滑动平均窗口 */
static int get_pt_slid_win(struct pt_ctrl_t *pctrl)
{
    int ret = 0;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_SAMP_SLID_WIN_OFFSET);
    pctrl->chk_slid_win = ((val & PT_SLID_WIN_MASK) >> PT_SLID_WIN_SHIFT);
    if (pctrl->chk_slid_win != pctrl->slid_win) {
        dev_err(pctrl->dev, "Get PT slide window %d, not the set %d", 
                pctrl->chk_slid_win, pctrl->slid_win);
        ret = -EFAULT;
        goto unlock;
    } else {
        dev_dbg(pctrl->dev, "Get PT slide window %d, is the set %d", 
                pctrl->chk_slid_win, pctrl->slid_win);
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 配置 PT 量程 */
static int set_pt_range(struct pt_dev_t *pdev, u8 range)
{
    struct pt_ctrl_t *pctrl = (struct pt_ctrl_t *)(pdev->parent);
    u8 range_code = range;
    u32 val = 0;

    switch (range) {
    case PT_RANGE_2V5:
        dev_dbg(pdev->dev, "Set PT%d range %s", pdev->index, "2.5V");
        break;
    case PT_RANGE_5V:
        dev_dbg(pdev->dev, "Set PT%d range %s", pdev->index, "5V");
        break;
    case PT_RANGE_10V0:
    case PT_RANGE_10V:
        dev_dbg(pdev->dev, "Set PT%d range %s", pdev->index, "10V");
        break;
    default:
        dev_warn(pdev->dev, "PT%d range %d not support, use default %s", pdev->index, range, "10V");
        range_code = PT_DEF_RANGE;
        break;
    }
    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    pdev->range = range_code;
    val = pctrl->read_reg(pctrl->pcie_dev, PT_RANGE_OFFSET);
    // val &= (~(PT_RANGE_MASK << pdev->index));
    // val |= (pdev->range << pdev->index);
    val &= (~(PT_RANGE_MASK << pctrl->id[pdev->index]));
    val |= (pdev->range << pctrl->id[pdev->index]);
    pctrl->write_reg(pctrl->pcie_dev, PT_RANGE_OFFSET, val);
    dev_dbg(pdev->dev, "Set PT%d range success", pdev->index);
    /* 配置 PT 参数 */
    config_pt_nolock(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return 0;
}

/* 获取 PT 量程 */
static int get_pt_range(struct pt_dev_t *pdev)
{
    struct pt_ctrl_t *pctrl = (struct pt_ctrl_t *)(pdev->parent);
    int ret = 0;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_RANGE_OFFSET);
    pdev->chk_range = ((val >> pctrl->id[pdev->index]) & PT_RANGE_MASK);
    if (pdev->chk_range != pdev->range) {
        dev_err(pdev->dev, "Get PT%d range %d, not the set %d", pdev->index, pdev->chk_range, pdev->range);
        ret = -EFAULT;
        goto unlock;
    } else {
        switch (pdev->chk_range) {
        case PT_RANGE_2V5:
            dev_dbg(pdev->dev, "Get PT%d range %s %d, is the set %d", 
                    pdev->index, "2.5V", pdev->chk_range, pdev->range);
            break;
        case PT_RANGE_5V:
            dev_dbg(pdev->dev, "Get PT%d range %s %d, is the set %d", 
                    pdev->index, "5V", pdev->chk_range, pdev->range);
            break;
        case PT_RANGE_10V0:
        case PT_RANGE_10V:
            dev_dbg(pdev->dev, "Get PT%d range %s %d, is the set %d", 
                    pdev->index, "10V", pdev->chk_range, pdev->range);
            break;
        default:
            dev_err(pdev->dev, "Get PT%d range %d not support", 
                     pdev->index, pdev->chk_range);
            break;
        }
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 获取 PT 指令 */
static int get_pt_cmd(struct pt_ctrl_t *pctrl)
{
    int ret = 0;
    u32 val = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    val = pctrl->read_reg(pctrl->pcie_dev, PT_CMD_OFFSET);
    pctrl->chk_cmd = ((val & PT_CMD_CODE_MASK) >> PT_CMD_CODE_SHIFT);
    if (pctrl->chk_cmd != pctrl->cmd) {
        dev_err(pctrl->dev, "Get PT cmd %d, not the set %d", 
                pctrl->chk_cmd, pctrl->cmd);
        ret = -EFAULT;
        goto unlock;
    } else {
        dev_dbg(pctrl->dev, "Get PT cmd %d, is the set %d", 
                pctrl->chk_cmd, pctrl->cmd);
    }

unlock:
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return ret;
}

/* 获取 PT 数据 */
static s32 get_pt_val(struct pt_dev_t *pdev)
{
    struct pt_ctrl_t *pctrl = (struct pt_ctrl_t *)(pdev->parent);
    u32 u32_val = 0;
    s32 s32_val = 0;
    u8 i = 0;
    u8 start = 0;
    u8 end = 0;

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&pctrl->lock)) {
        dev_err(pctrl->dev, "Acquire %s %s mutex failed", __func__, pctrl->name);
        return -ERESTARTSYS;
    }
    if (pctrl->mode == PT_MOD_SMP_TIM) {
        start = 0;
        end = pctrl->num;
    } else {
        start = pdev->index;
        end = pdev->index + 1;
    }
    /* 禁用 PT DMA MSI 中断 */
    // disable_pt_dma_msi_irq(pctrl);
    for (i = start; i < end; i++) {
        u32_val = 0;
        u32_val &= PT_ID_MASK;
        u32_val |= (pctrl->id[i] << PT_ID_SHIFT);
        pctrl->write_reg(pctrl->pcie_dev, PT_CH_VAL_OFFSET, u32_val);
        u32_val = pctrl->read_reg(pctrl->pcie_dev, PT_CH_VAL_OFFSET);
        s32_val = (s32)(u32_val & PT_DATA_MASK);
        /* 24bit 有符号数据转换为 32bit 有符号数据 */
        if ((s32_val & PT_DATA_SIGN_MASK) == PT_DATA_SIGN_MASK) {
            s32_val |= (~PT_DATA_MASK);
        }
        s32_val /= pctrl->slid_win;
        switch (pdev->range) {
        case PT_RANGE_2V5:
            s32_val *= PT_RANGE_2V5_LSB;
            dev_dbg(pdev->dev, "Get PT%d(AI%d)=%duV(2.5V).", i, pctrl->id[i], s32_val);
            break;
        case PT_RANGE_5V:
            s32_val *= PT_RANGE_5V_LSB;
            dev_dbg(pdev->dev, "Get PT%d(AI%d)=%duV(5V).", i, pctrl->id[i], s32_val);
            break;
        case PT_RANGE_10V0:
        case PT_RANGE_10V:
            s32_val *= PT_RANGE_10V_LSB;
            dev_dbg(pdev->dev, "Get PT%d(AI%d)=%duV(10V).", i, pctrl->id[i], s32_val);
            break;
        default:
            dev_warn(pdev->dev, "Get PT%d(AI%d)=%duV(range error).", i, pctrl->id[i], s32_val);
            break;
        }
        pctrl->val[i] = s32_val;
    }
    /* 使能 PT DMA MSI 中断 */
    // enable_pt_dma_msi_irq(pctrl);
    /* 释放互斥锁 */
    mutex_unlock(&pctrl->lock);

    return s32_val;
}

/* 打开设备 */
static int open_pt(struct inode *inode, struct file *filp)
{
    /* 获取与 inode 关联的字符设备 */
    struct cdev_dev_t *cdev_dev = container_of(inode->i_cdev, struct cdev_dev_t, cdev);
    struct cdev_ctrl_t *cdev_ctrl = (struct cdev_ctrl_t *)(cdev_dev->parent);
    struct pt_ctrl_t *pctrl = (struct pt_ctrl_t *)(cdev_ctrl->parent);
    struct pt_dev_t *priv = &pctrl->pt[cdev_dev->index];

    /* 检查设备是否有效 */
    if (!priv || !priv->dev) {
        pr_err("Invalid parameters for %s", __func__);
        return -ENODEV;
    }
    /* 记录设备指针 */
    filp->private_data = priv;
    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&priv->lock)) {
        dev_err(priv->dev, "Acquire %s mutex failed", cdev_dev->name);
        return -ERESTARTSYS;
    }
    /* 开始 PT 采集 */
    start_pt_nolock(pctrl);
    dev_info(priv->dev, "Open %s%d device", cdev_ctrl->name, cdev_dev->index);

    mutex_unlock(&priv->lock);

    return 0;
}

/* 关闭设备 */
static int release_pt(struct inode *inode, struct file *filp)
{
    struct pt_dev_t *priv = filp->private_data;

    if (priv) {
        mutex_lock(&priv->lock);
        dev_info(priv->dev, "Release %s device", priv->name);
        mutex_unlock(&priv->lock);
    }

    return 0;
}

/* 读取设备 */
static ssize_t read_pt(struct file *filp, char __user *buf, 
                       size_t count, loff_t *ppos)
{
    struct pt_dev_t *priv = filp->private_data;
    struct pt_ctrl_t *pctrl = (struct pt_ctrl_t *)(priv->parent);
    ssize_t ret = 0;
    size_t read_len = 0;
    s32 s32_val = 0;

    /* 检查参数是否有效 */
    if (!priv || !priv->dev || !buf) {
        pr_err("Invalid parameters for %s", __func__);
        return -ENODEV;
    }

    /* 检查偏移量是否有效 */
    if (*ppos > sizeof(u64)) {
        dev_err(priv->dev, "Beyond buffer size, pos=%lld, size=%zu", 
                *ppos, sizeof(u64));
        return -EFBIG;
    }

    /* 计算实际可读取长度 */
    read_len = min(count, (size_t)(sizeof(u64) - *ppos));

    /* 获取 PI 频率值 */
    s32_val = get_pt_val(priv);
    if (copy_to_user(buf, &pctrl->val[priv->index], sizeof(s32_val))) {
        dev_err(priv->dev, "Copy %s %zu data to user space failed", priv->name, read_len);
        goto unlock;
    }
    dev_dbg(priv->dev, "Read %s %zu data from offset %lld", 
            priv->name, read_len, *ppos);
    /* 更新文件位置 */
    // *ppos += read_len;
    ret = read_len;

unlock:
    mutex_unlock(&priv->lock);

    return ret;
}

/* IOCTL 处理 */
static long ioctl_pt(struct file *filp, unsigned int cmd, 
                          unsigned long arg)
{
    struct pt_dev_t *priv = filp->private_data;
    struct pt_ctrl_t *pctrl = (struct pt_ctrl_t *)(priv->parent);
    long ret = 0;
    u8 u8_val = 0;
    u16 u16_val = 0;
    u32 u32_val = 0;
    s32 s32_val = 0;

    /* 检查参数是否有效 */
    if (!priv || !priv->dev) {
        pr_err("Invalid parameters for %s", __func__);
        return -ENODEV;
    }

    /* 获取互斥锁 */
    if (mutex_lock_interruptible(&priv->lock)) {
        dev_err(priv->dev, "Acquire %s %s mutex failed", __func__, priv->name);
        return -ERESTARTSYS;
    }
    switch (cmd) {
    /* 配置 PT 模式 */
    case IOCTL_PT_SET_MODE:
        if (copy_from_user(&u8_val, (void __user *)arg, sizeof(u8_val))) {
            dev_err(priv->dev, "Set PT mode copy failed");
            ret = -EFAULT;
            goto unlock;
        }
        if (set_pt_mode(pctrl, u8_val) < 0) {
            dev_err(priv->dev, "Set PT mode %d failed", u8_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 模式 */
    case IOCTL_PT_CHK_MODE:
        if (get_pt_mode(pctrl) < 0) {
            dev_err(priv->dev, "Get PT mode %d failed", pctrl->chk_mode);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &pctrl->chk_mode, sizeof(pctrl->chk_mode))) {
            dev_err(priv->dev, "Get PT mode %d copy failed", pctrl->chk_mode);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 配置 PT 过采样 */
    case IOCTL_PT_SET_OSR:
        if (copy_from_user(&u8_val, (void __user *)arg, sizeof(u8_val))) {
            dev_err(priv->dev, "Set PT OSR copy failed");
            ret = -EFAULT;
            goto unlock;
        }
        if (set_pt_osr(pctrl, u8_val) < 0) {
            dev_err(priv->dev, "Set PT OSR %d failed", u8_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 过采样 */
    case IOCTL_PT_CHK_OSR:
        if (get_pt_osr(pctrl) < 0) {
            dev_err(priv->dev, "Get PT OSR %d failed", pctrl->chk_mode);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &pctrl->chk_osr, sizeof(pctrl->chk_osr))) {
            dev_err(priv->dev, "Get PT OSR %d copy failed", pctrl->chk_osr);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 配置 PT 采样率 */
    case IOCTL_PT_SET_SAMP_RATE:
        if (copy_from_user(&u32_val, (void __user *)arg, sizeof(u32_val))) {
            dev_err(priv->dev, "Set PT sample rate copy failed");
            ret = -EFAULT;
            goto unlock;
        }
        if (set_pt_samp_rate(pctrl, u32_val) < 0) {
            dev_err(priv->dev, "Set PT sample rate %dus failed", u32_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 采样率 */
    case IOCTL_PT_CHK_SAMP_RATE:
        if (get_pt_samp_rate(pctrl) < 0) {
            dev_err(priv->dev, "Get PT sample rate %d failed", pctrl->chk_samp_rate);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &pctrl->chk_samp_rate, sizeof(pctrl->chk_samp_rate))) {
            dev_err(priv->dev, "Get PT sample rate %d copy failed", pctrl->chk_samp_rate);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 配置 PT 抽样定时间隔 */
    case IOCTL_PT_SET_IRQ_RATE:
        if (copy_from_user(&u16_val, (void __user *)arg, sizeof(u16_val))) {
            dev_err(priv->dev, "Set PT sample time failed");
            ret = -EFAULT;
            goto unlock;
        }
        if (set_pt_samp_tim(pctrl, u16_val) < 0) {
            dev_err(priv->dev, "Set PT sample time %dus failed", u16_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 抽样定时间隔 */
    case IOCTL_PT_CHK_IRQ_RATE:
        if (get_pt_samp_tim(pctrl) < 0) {
            dev_err(priv->dev, "Get PT sample time %d failed", pctrl->chk_samp_tim);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &pctrl->chk_samp_tim, sizeof(pctrl->chk_samp_tim))) {
            dev_err(priv->dev, "Get PT sample time %d copy failed", pctrl->chk_samp_tim);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 配置 PT 滑动平均窗口 */
    case IOCTL_PT_SET_SLID_WIN:
        if (copy_from_user(&u16_val, (void __user *)arg, sizeof(u16_val))) {
            dev_err(priv->dev, "Set PT slide window failed");
            ret = -EFAULT;
            goto unlock;
        }
        if (set_pt_slid_win(pctrl, u16_val) < 0) {
            dev_err(priv->dev, "Set PT slide window %d failed", u16_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 滑动平均窗口 */
    case IOCTL_PT_CHK_SLID_WIN:
        if (get_pt_slid_win(pctrl) < 0) {
            dev_err(priv->dev, "Get PT slide window %d failed", pctrl->chk_slid_win);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &pctrl->chk_slid_win, sizeof(pctrl->chk_slid_win))) {
            dev_err(priv->dev, "Get PT slide window %d copy failed", pctrl->chk_slid_win);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 配置 PT 量程 */
    case IOCTL_PT_SET_RANGE:
        if (copy_from_user(&u8_val, (void __user *)arg, sizeof(u8_val))) {
            dev_err(priv->dev, "Set PT%d range copy failed", priv->index);
            ret = -EFAULT;
            goto unlock;
        }
        if (set_pt_range(priv, u8_val) < 0) {
            dev_err(priv->dev, "Set PT%d range %d failed", priv->index, u8_val);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 量程 */
    case IOCTL_PT_CHK_RANGE:
        if (get_pt_range(priv) < 0) {
            dev_err(priv->dev, "Get PT%d range %d failed", priv->index, priv->chk_range);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &priv->chk_range, sizeof(priv->chk_range))) {
            dev_err(priv->dev, "Get PT%d range %d copy failed", priv->index, priv->chk_range);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 PT 数值 */
    case IOCTL_PT_GET_VAL:
        /* 获取 PT 数据 */
        s32_val = get_pt_val(priv);
        if (copy_to_user((void __user *)arg, &s32_val, sizeof(s32_val))) {
            dev_err(priv->dev, "Get PT%d=%duV copy failed", priv->index, pctrl->val[priv->index]);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 开始 PT 采集 */
    case IOCTL_PT_START:
        start_pt_nolock(pctrl);
        break;
    /* 停止 PT 采集 */
    case IOCTL_PT_STOP:
        stop_pt_nolock(pctrl);
        break;
    /* 获取 PT 量程 */
    case IOCTL_PT_CHK_CMD:
        if (get_pt_cmd(pctrl) < 0) {
            dev_err(pctrl->dev, "Get PT cmd %d failed", pctrl->chk_cmd);
            ret = -EFAULT;
            goto unlock;
        }
        if (copy_to_user((void __user *)arg, &pctrl->chk_cmd, sizeof(pctrl->chk_cmd))) {
            dev_err(pctrl->dev, "Get PT cmd %d copy failed", pctrl->chk_cmd);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取驱动版本号 */
    case IOCTL_PT_GET_DRV_VERSION:
        if (copy_to_user((void __user *)arg, &pctrl->drv_ver, sizeof(pctrl->drv_ver))) {
            dev_err(pctrl->dev, "Get PT driver version %d copy failed", pctrl->drv_ver);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    /* 获取 FPGA 版本号 */
    case IOCTL_PT_GET_FPGA_VERSION:
        if (copy_to_user((void __user *)arg, &pctrl->fpga_ver, sizeof(pctrl->fpga_ver))) {
            dev_err(pctrl->dev, "Get PT FPGA version %d copy failed", pctrl->fpga_ver);
            ret = -EFAULT;
            goto unlock;
        }
        break;
    default:
        dev_err(priv->dev, "Ioctl PT%d cmd=0x%08x, dir=0x%X, size=%u, type=0x%02X('%c'), nr=%u not support\n",
                priv->index, cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd), _IOC_TYPE(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd));
        ret = -ENOTTY;
        break;
    }

unlock:
    mutex_unlock(&priv->lock);

    return ret;
}

/* 初始化 PT 设备 */
static int init_pt_dev(void *parent, struct device *dev, const char *name, 
                       struct pt_dev_t *pt, u8 index, u8 range)
{
    int ret = 0;

    pt->parent = parent;
    pt->dev = dev;
    /* 初始化互斥锁 */
    mutex_init(&pt->lock);
    strscpy(pt->name, name, sizeof(pt->name));
    pt->index = index;

    pt->range = range;
    /* 配置 PT 量程 */
    set_pt_range(pt, range);

    return ret;
}

/* 初始化 PT 控制器 */
int init_pt_ctrl(struct pcie_dev_t *pcie_dev, struct cdev_dev_t *cdev_dev, 
                 struct pt_ctrl_t *pctrl, struct pt_dev_t *pt, 
                 const char *ctrl_name, u8 dev_num)
{
    int ret = 0;
    int i = 0;
    char name[32];

    pctrl->dev = &pcie_dev->pdev->dev;
    /* 初始化互斥锁 */
    mutex_init(&pctrl->lock);
    snprintf(pctrl->name, sizeof(pctrl->name), "%s", ctrl_name);
    pctrl->num = dev_num;
    pctrl->pcie_dev = pcie_dev;
    pctrl->read_reg = read_pt_reg_le;
    pctrl->write_reg = write_pt_reg_le;
    pctrl->cdev_ctrl.cdev_dev = cdev_dev;
    pctrl->pt = pt;
    pctrl->type = PT_TYPE_PT100;
    switch (pctrl->type) {
    case PT_TYPE_AC:
        for (i = 0; i < dev_num; i++) {
            pctrl->id[i] = i;
        }
        break;
    case PT_TYPE_PT100:
        pctrl->id[0] = 0;
        pctrl->id[1] = 1;
        pctrl->id[2] = 2;
        pctrl->id[3] = 3;
        pctrl->id[4] = 4;
        pctrl->id[5] = 5;
        pctrl->id[6] = 6;
        pctrl->id[7] = 7;
        break;
    case PT_TYPE_AI:
    default:
        for (i = 0; i < dev_num; i++) {
            pctrl->id[i] = i;
        }
        break;
    }
    pctrl->drv_ver = CDEV_DRV_VERSION(PT_VER_MAJOR, PT_VER_MINOR, PT_VER_PATCH);
    pctrl->fpga_ver = pcie_dev->read_mem(pcie_dev->bar[0] + PT_VERSION_OFFSET);

    /* 初始化字符设备 */
    ret = init_cdev_ctrl(pctrl, &pctrl->cdev_ctrl, pctrl->name, dev_num);
    if (ret < 0) {
        dev_err(pctrl->dev, "Init %s controller failed", pctrl->name);
        goto err_free_dev;
    }
    for (i = 0; i < dev_num; i++) {
        snprintf(name, sizeof(name), "%s%d", pctrl->name, i);
        ret = init_cdev_dev(&pctrl->cdev_ctrl, pctrl->cdev_ctrl.cclass, 
                            &pctrl->cdev_ctrl.cdev_dev[i], &cdev_fops, pctrl->cdev_ctrl.major_devno, name, i);
        if (ret) {
            dev_err(pctrl->dev, "Init %s device failed", name);
            goto err_cleanup_cdev_ctrl;
        }
    }

    /* 初始化 PT 设备*/
    set_pt_mode(pctrl, PT_DEF_MODE);                /* 配置 PT 模式 */
    set_pt_osr(pctrl, PT_DEF_OSR);                  /* 配置 PT 过采样 */
    set_pt_samp_rate(pctrl, PT_DEF_SAMPLE);         /* 配置 PT 采样间隔时间 */
    set_pt_samp_tim(pctrl, PT_DEF_SAMP_TIM);        /* 配置 PT 抽样定时间隔 */
    set_pt_slid_win(pctrl, PT_DEF_SLID_WIN);        /* 配置 PT 滑动平均窗口 */
    for (i = 0; i < dev_num; i++) {
        init_pt_dev(pctrl, pctrl->dev, pctrl->cdev_ctrl.cdev_dev[i].name, 
                    &pctrl->pt[i], i, PT_DEF_RANGE);
    }

    return 0;

err_cleanup_cdev_ctrl:
    exit_cdev_ctrl(&pctrl->cdev_ctrl);
err_free_dev:

    return ret;
}

/* 注销 PT 控制器 */
void exit_pt_ctrl(struct pt_ctrl_t *pctrl, u8 dev_num)
{
    u8 i = 0;

    if (!pctrl) {
        pr_err("Invalid parameters for %s", __func__);
        return;
    }

    for (i = 0; i < dev_num; i++) {
        exit_cdev_dev(pctrl->cdev_ctrl.cclass, &pctrl->cdev_ctrl.cdev_dev[i]);
    }
    exit_cdev_ctrl(&pctrl->cdev_ctrl);
    dev_info(pctrl->dev, "Release cdev controller success");

    for (i = 0; i < dev_num; i++) {
        mutex_destroy(&pctrl->pt[i].lock);
    }
    /* 注销互斥锁 */
    mutex_destroy(&pctrl->lock);

    dev_info(pctrl->dev, "PCIe character device %s removed", pctrl->name);
}
